Fix detached --status resurrecting a killed (exit 137) record back to 'executing'#135
Conversation
Adding .gitkeep for PR creation (default mode). This file will be removed when the task is complete. Issue: #134
enrichDetachedStatus / enrich_detached_status flipped an already-completed detached record (status 'executed', exitCode 137) back to 'executing' and nulled the exit code whenever screen -ls / tmux / docker still listed a same-named session. A lingering shell can outlive a SIGKILLed command (e.g. OOM kill), so liveness is not equivalent to 'the command is running'. The 'Exit Code:' footer start itself writes is authoritative. Now the record only flips back to 'executing' when there is no recorded terminal exit code AND no Exit Code footer in the log, mirroring the existing logic in the opposite (!alive && executing) branch. Fixes #134
Working session summaryThe work is complete. Here's a summary of what I did to solve issue #134: Root cause
FixIn the
Tests (regression)Added tests in both languages that start a real
I verified each fails on Release
PR #135 is updated with a full description and marked ready for review: #135 This summary was automatically extracted from the AI working session output. |
🤖 Solution Draft LogThis log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (7.0K new + 55.2K cache writes + 2.0M cache reads) input tokens, 14.9K output tokens, $1.760882 cost 🤖 Models used:
📎 Log file uploaded as Gist (1187KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
🔄 Auto-restart triggered (iteration 1)Reason: CI failures detected Starting new session to address the issues. Auto-restart-until-mergeable mode is active. This run will stop after 5 restart iterations. |
…sn't observable Under cargo-tarpaulin's ptrace tracing the 'screen -dmS' daemon fork is disrupted, so the session never registers in 'screen -ls' and the sanity precondition cannot hold. Skip gracefully instead of hard-failing; plain 'cargo test' still exercises the assertions.
Working session summaryAll checks pass now, including the previously-failing Changelog Fragment Check and the Code Coverage (Rust, Linux only) job. The remaining SummaryThe CI failure had two layers:
Commits pushed to
PR: #135 — all checks green. This summary was automatically extracted from the AI working session output. |
🔄 Auto-restart-until-mergeable Log (iteration 1)This log file contains the complete execution trace of the AI solution draft process. 💰 Cost estimation:
📊 Context and tokens usage:
Total: (3.3K new + 50.7K cache writes + 1.3M cache reads) input tokens, 11.3K output tokens, $1.257411 cost 🤖 Models used:
📎 Log file uploaded as Gist (2099KB)Now working session is ended, feel free to review and add any feedback on the solution draft. |
✅ Ready to mergeThis pull request is now ready to be merged:
Monitored by hive-mind with --auto-restart-until-mergeable flag |
Summary
Fixes #134.
enrichDetachedStatus()(JS) /enrich_detached_status()(Rust) could flip an already-completed detached record (status: 'executed',exitCode: 137) back to'executing'and null out the real exit code, purely becausescreen -ls(ortmux/docker) still listed a session of the same name.A live session is not equivalent to "the command is still running": a lingering shell (or a child that ignored the signal, or just the login shell) can outlive a
SIGKILLed command — e.g. an OOM kill (exit137) — for a window afterstarthas already written the terminal footer. As a result,$ <id> --statusreported a dead, OOM-killed command as still running, indefinitely (see link-assistant/hive-mind#1927).The asymmetry was the giveaway: the
!alive && executingbranch already treats the log footer as authoritative (readExitCodeFromLog), but thealive && executedbranch never consulted it.The fix
In the
alive && executedbranch, consult the recorded exit code and theExit Code:log footer before flipping. The record now flips back toexecutingonly when there is no recorded terminal exit code and no footer in the log — otherwise the recorded/footer exit code wins, because a lingering shell is not a running command.Applied identically in both implementations to preserve JS/Rust parity:
js/src/lib/status-formatter.jsrust/src/lib/status_formatter.rsReproduction & tests
Added regression tests that start a real
screensession which outlives an already-finished command, with a log footer exactly asstartwrites for a killed command:js/test/session-name-status.js— Issue Detached --status: enrichDetachedStatus flips a completed (killed, exit 137) record back to 'executing' and nulls the exit code #134 block (3 cases)rust/tests/session_name_status.rs—test_enrich_*(3 cases)Each covers:
exitCode: 137+ live session → staysexecuted/137Exit Code: 137→ staysexecutedexecutingAll three fail on
main(cases 1 & 2) and pass with the fix. Verified by reverting the source change:Full suites green: JS
660 pass / 0 fail, Rustcargo testgreen,cargo fmt --check+cargo clippyclean, JS eslint/prettier clean.Release
js/.changeset/detached-status-killed-record.md(patch) for the JS package.Cargo.tomlversion intentionally not bumped — CI (rust.ymlversion-check) prohibits manual version changes; the release workflow bumps it automatically on merge.References
$ --status 14a0e075-3de1-4342-97cd-f87c8cd66ddashows command is still executing, while it actually wasFinished at 2026-01-07 19:29:07.663#60, Bug: --session name not usable with --status, and --detached reports immediate completion #101 — prior--detachedstatus reconciliation that introducedenrichDetachedStatus.killedlink-assistant/hive-mind#1927, fix(telegram): detect OOM/SIGKILL-ed detached sessions + resume tracking after a bot restart (#1927) link-assistant/hive-mind#1928.